home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / swtools / mipsABI / examples / sup / PORT / step07 / expand.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  7.8 KB  |  379 lines

  1. /*
  2.  * Copyright (c) 1991 Carnegie Mellon University
  3.  * All Rights Reserved.
  4.  * 
  5.  * Permission to use, copy, modify and distribute this software and its
  6.  * documentation is hereby granted, provided that both the copyright
  7.  * notice and this permission notice appear in all copies of the
  8.  * software, derivative works or modified versions, and any portions
  9.  * thereof, and that both notices appear in supporting documentation.
  10.  *
  11.  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  12.  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  13.  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  14.  *
  15.  * Carnegie Mellon requests users of this software to return to
  16.  *
  17.  *  Software Distribution Coordinator   or   Software.Distribution@CS.CMU.EDU
  18.  *  School of Computer Science
  19.  *  Carnegie Mellon University
  20.  *  Pittsburgh PA 15213-3890
  21.  *
  22.  * any improvements or extensions that they make and grant Carnegie the rights
  23.  * to redistribute these changes.
  24.  */
  25. /*
  26.  *  expand - expand wildcard filename specifications
  27.  *
  28.  *  Usage:
  29.  *    int expand(spec, buffer, bufsize);
  30.  *    char *spec, **buffer;
  31.  *    int bufsize;
  32.  *
  33.  *  Expand takes a file specification, and expands it into filenames
  34.  *  by resolving the characters '*', '?', '[', ']', '{', '}' and '~'
  35.  *  in the same manner as the shell.  You provide "buffer", which is
  36.  *  an array of char *'s, and you tell how big it is in bufsize.
  37.  *  Expand will compute the corresponding filenames, and will fill up
  38.  *  the entries of buffer with pointers to malloc'd strings.
  39.  *
  40.  *  The value returned by expand is the number of filenames found.  If
  41.  *  this value is -1, then malloc failed to allocate a string.  If the
  42.  *  value is bufsize + 1, then too many names were found and you can try
  43.  *  again with a bigger buffer.
  44.  *
  45.  *  This routine was basically created from the csh sh.glob.c file with
  46.  *  the following intended differences:
  47.  *
  48.  *    Filenames are not sorted.
  49.  *    All expanded filenames returned exist.
  50.  *
  51.  **********************************************************************
  52.  * HISTORY
  53.  * 13-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  54.  *    Replaced a stat() with lstat() and changed glob() to only call
  55.  *    matchdir() for directories.
  56.  *
  57.  * 20-Oct-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  58.  *    Created from csh glob() function and 4.1 expand() function.
  59.  *
  60.  **********************************************************************
  61.  */
  62. #include <sys/param.h>
  63. #include <sys/stat.h>
  64. #ifdef _ABI_SOURCE
  65. #include <dirent.h>
  66. #else
  67. #include <sys/dir.h>
  68. #endif
  69. #include <pwd.h>
  70. #include <ctype.h>
  71. #include <libc.h>
  72. #include <setjmp.h>
  73.  
  74. #if __STDC__
  75. static glob(char *);
  76. static matchdir(char *);
  77. static execbrc(char *, char *);
  78. static match(char *, char *);
  79. static amatch(char *, char *);
  80. static addone(char *, char *);
  81. static addpath(char);
  82. static gethdir(char *);
  83. #endif
  84.  
  85. static    jmp_buf    sjbuf;
  86.  
  87. static    char    pathbuf[MAXPATHLEN];
  88. static    char    *path, *pathp, *lastpathp;
  89.  
  90. static    char    *globchars = "{[*?";    /* meta characters */
  91. static    char    *entp;            /* current dir entry pointer */
  92.  
  93. static    char    **BUFFER;        /* pointer to the buffer */
  94. static    int    BUFSIZE;        /* maximum number in buffer */
  95. static    int    bufcnt;            /* current number in buffer */
  96.  
  97. int expand(spec, buffer, bufsize)
  98.     register char *spec;
  99.     char **buffer;
  100.     int bufsize;
  101. {
  102.     pathp = path = pathbuf;
  103.     *pathp = 0;
  104.     lastpathp = &path[MAXPATHLEN - 2];
  105.     BUFFER = buffer;
  106.     BUFSIZE = bufsize;
  107.     bufcnt = 0;
  108.     if (setjmp(sjbuf) == 0)
  109.         glob(spec);
  110.     return(bufcnt);
  111. }
  112.  
  113. static glob(as)
  114.     char *as;
  115. {
  116.     register char *cs;
  117.     register char *spathp, *oldcs;
  118.     struct stat stb;
  119.  
  120.     spathp = pathp;
  121.     cs = as;
  122.     if (*cs == '~' && pathp == path) {
  123.         if (addpath('~')) goto endit;
  124.         for (cs++; isalnum(*cs) || *cs == '_' || *cs == '-';)
  125.             if (addpath(*cs++)) goto endit;
  126.         if (!*cs || *cs == '/') {
  127.             if (pathp != path + 1) {
  128.                 *pathp = 0;
  129.                 if (gethdir(path + 1)) goto endit;
  130.                 strcpy(path, path + 1);
  131.             } else
  132.                 strcpy(path, (char *)getenv("HOME"));
  133.             pathp = path;
  134.             while (*pathp) pathp++;
  135.         }
  136.     }
  137.     while (*cs == 0 || index(globchars, *cs) == 0) {
  138.         if (*cs == 0) {
  139.             if (lstat(path, &stb) >= 0) addone(path, "");
  140.             goto endit;
  141.         }
  142.         if (addpath(*cs++)) goto endit;
  143.     }
  144.     oldcs = cs;
  145.     while (cs > as && *cs != '/')
  146.         cs--, pathp--;
  147.     if (*cs == '/')
  148.         cs++, pathp++;
  149.     *pathp = 0;
  150.     if (*oldcs == '{') {
  151.         execbrc(cs, NULL);
  152.         return;
  153.     }
  154.     /* this should not be an lstat */
  155.     if (stat(path, &stb) >= 0 && (stb.st_mode&S_IFMT) == S_IFDIR)
  156.         matchdir(cs);
  157. endit:
  158.     pathp = spathp;
  159.     *pathp = 0;
  160.     return;
  161. }
  162.  
  163. static matchdir(pattern)
  164.     char *pattern;
  165. {
  166. #ifdef _ABI_SOURCE
  167.     register struct dirent *dp;
  168. #else
  169.     register struct direct *dp;
  170. #endif
  171.     DIR *dirp;
  172.  
  173.     dirp = opendir(path);
  174.     if (dirp == NULL)
  175.         return;
  176.     while ((dp = readdir(dirp)) != NULL) {
  177.         if (dp->d_ino == 0) continue;
  178.         if (match(dp->d_name, pattern))
  179.             addone(path, dp->d_name);
  180.     }
  181.     closedir(dirp);
  182.     return;
  183. }
  184.  
  185. static execbrc(p, s)
  186.     char *p, *s;
  187. {
  188.     char restbuf[MAXPATHLEN + 1];
  189.     register char *pe, *pm, *pl;
  190.     int brclev = 0;
  191.     char *lm, savec, *spathp;
  192.  
  193.     for (lm = restbuf; *p != '{'; *lm++ = *p++)
  194.         continue;
  195.     for (pe = ++p; *pe; pe++)
  196.     switch (*pe) {
  197.     case '{':
  198.         brclev++;
  199.         continue;
  200.     case '}':
  201.         if (brclev == 0) goto pend;
  202.         brclev--;
  203.         continue;
  204.     case '[':
  205.         for (pe++; *pe && *pe != ']'; pe++)
  206.             continue;
  207.         if (!*pe) break;
  208.         continue;
  209.     }
  210. pend:
  211.     if (brclev || !*pe) return (0);
  212.     for (pl = pm = p; pm <= pe; pm++)
  213.         switch (*pm & 0177) {
  214.         case '{':
  215.             brclev++;
  216.             continue;
  217.         case '}':
  218.             if (brclev) {
  219.                 brclev--;
  220.                 continue;
  221.             }
  222.             goto doit;
  223.         case ',':
  224.             if (brclev) continue;
  225. doit:
  226.             savec = *pm;
  227.             *pm = 0;
  228.             strcpy(lm, pl);
  229.             strcat(restbuf, pe + 1);
  230.             *pm = savec;
  231.             if (s == 0) {
  232.                 spathp = pathp;
  233.                 glob(restbuf);
  234.                 pathp = spathp;
  235.                 *pathp = 0;
  236.             } else if (amatch(s, restbuf))
  237.                 return (1);
  238.             pl = pm + 1;
  239.             continue;
  240.  
  241.         case '[':
  242.             for (pm++; *pm && *pm != ']'; pm++)
  243.                 continue;
  244.             if (!*pm) break;
  245.             continue;
  246.         }
  247.     return (0);
  248. }
  249.  
  250. static match(s, p)
  251.     char *s, *p;
  252. {
  253.     register int c;
  254.     register char *sentp;
  255.  
  256.     if (*s == '.' && *p != '.') return(0);
  257.     sentp = entp;
  258.     entp = s;
  259.     c = amatch(s, p);
  260.     entp = sentp;
  261.     return (c);
  262. }
  263.  
  264. static amatch(s, p)
  265.     register char *s, *p;
  266. {
  267.     register int scc;
  268.     int ok, lc;
  269.     char *spathp;
  270.     struct stat stb;
  271.     int c, cc;
  272.  
  273.     for (;;) {
  274.         scc = *s++ & 0177;
  275.         switch (c = *p++) {
  276.         case '{':
  277.             return (execbrc(p - 1, s - 1));
  278.         case '[':
  279.             ok = 0;
  280.             lc = 077777;
  281.             while (cc = *p++) {
  282.                 if (cc == ']') {
  283.                     if (ok) break;
  284.                     return (0);
  285.                 }
  286.                 if (cc == '-') {
  287.                     if (lc <= scc && scc <= *p++)
  288.                         ok++;
  289.                 } else
  290.                     if (scc == (lc = cc))
  291.                         ok++;
  292.             }
  293.             if (cc == 0) return (0);
  294.             continue;
  295.         case '*':
  296.             if (!*p) return (1);
  297.             if (*p == '/') {
  298.                 p++;
  299.                 goto slash;
  300.             }
  301.             for (s--; *s; s++)
  302.                 if (amatch(s, p))
  303.                     return (1);
  304.             return (0);
  305.         case 0:
  306.             return (scc == 0);
  307.         default:
  308.             if (c != scc) return (0);
  309.             continue;
  310.         case '?':
  311.             if (scc == 0) return (0);
  312.             continue;
  313.         case '/':
  314.             if (scc) return (0);
  315. slash:
  316.             s = entp;
  317.             spathp = pathp;
  318.             while (*s)
  319.                 if (addpath(*s++)) goto pathovfl;
  320.             if (addpath('/')) goto pathovfl;
  321.             if (stat(path, &stb) >= 0 &&
  322.                 (stb.st_mode&S_IFMT) == S_IFDIR)
  323.                 if (*p == 0)
  324.                     addone(path, "");
  325.                 else
  326.                     glob(p);
  327. pathovfl:
  328.             pathp = spathp;
  329.             *pathp = 0;
  330.             return (0);
  331.         }
  332.     }
  333. }
  334.  
  335. static addone(s1, s2)
  336.     register char *s1, *s2;
  337. {
  338.     register char *ep;
  339.  
  340.     if (bufcnt >= BUFSIZE) {
  341.         bufcnt = BUFSIZE + 1;
  342.         longjmp(sjbuf, 1);
  343.     }
  344.     ep = (char *)malloc(strlen(s1) + strlen(s2) + 1);
  345.     if (ep == 0) {
  346.         bufcnt = -1;
  347.         longjmp(sjbuf, 1);
  348.     }
  349.     BUFFER[bufcnt++] = ep;
  350.     while (*s1) *ep++ = *s1++;
  351.     while (*ep++ = *s2++);
  352. }
  353.  
  354. #ifdef __STDC__
  355. static addpath(char c)
  356. #else
  357. static addpath(c)
  358.     char c;
  359. #endif
  360. {
  361.     if (pathp >= lastpathp)
  362.         return(1);
  363.     *pathp++ = c;
  364.     *pathp = 0;
  365.     return(0);
  366. }
  367.  
  368. static gethdir(home)
  369.     char *home;
  370. {
  371.     struct passwd *getpwnam();
  372.     register struct passwd *pp = getpwnam(home);
  373.  
  374.     if (pp == 0)
  375.         return(1);
  376.     strcpy(home, pp->pw_dir);
  377.     return(0);
  378. }
  379.